﻿//===============================================================================
// Magic OQL
//===============================================================================
// Copyright ?Magic Thought Corporation. All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// Richie (http://www.cnblogs.com/RicCC)
// March 5, 2008
//===============================================================================
// This class is ported from Antlr3.Runtime written by Kunle Odutola. (BaseTreeAdaptor & CommonTreeAdaptor)
//===============================================================================

using System;
using System.Collections.Generic;
using Antlr.Runtime;
using Antlr.Runtime.Tree;
using Magic.Framework.OQL.Expressions;

namespace Magic.Framework.OQL.Factory
{
    public class TreeFactory : ITreeAdaptor
    {
        private static IDictionary<int, IExpressionFactory> _factories;
        public int startIndex;
        public int stopIndex;
        protected IToken token;

        #region constructors
        /// <summary>
        /// Custom factories used to create OQL expressions.
        /// </summary>
        static TreeFactory()
        {
            //Using reflection can simply reduce code
            //Taking this approach not only for performance consideration, I just don't know what's I wanted and how to...
            //The process of building AST tree was moved to the inheritance hierarchy of Expression, and the AST
            //construction in grammar, this weaken the factory.
            //Maybe it will become usefull in coming days.
            _factories = new Dictionary<int, IExpressionFactory>();

            _factories.Add(SQLParser.SelectStmt, new SelectStatementFactory());

            _factories.Add(SQLParser.SelectClause, new SelectClauseFactory());
            _factories.Add(SQLParser.FROM, new FromClauseFactory());
            _factories.Add(SQLParser.WhereClause, new WhereClauseFactory());
            
            _factories.Add(SQLParser.Table, new TableFactory());
           
            _factories.Add(SQLParser.Column, new ColumnFactory());

            _factories.Add(SQLParser.Predicate, new ComparisonFactory());
           
            _factories.Add(SQLParser.AND, new AndFactory());
            _factories.Add(SQLParser.OR, new OrFactory());
            _factories.Add(SQLParser.NOT, new NotFactory());
           
            _factories.Add(SQLParser.TextNode, new TextFactory());
            _factories.Add(SQLParser.Group, new ConditionGroupFactory());
           
        }

        public TreeFactory()
        {
        }
        public TreeFactory(IToken node)
        {
        }
        #endregion

        #region members for ITreeAdaptor
        public virtual void ReplaceChildren(object parent, int startChildIndex, int stopChildIndex, object t)
        {
            if (parent != null)
            {
                ((ITree)parent).ReplaceChildren( startChildIndex, stopChildIndex, t);
            }
        }
        public virtual void SetChildIndex(object t, int index)
        {
            if (t != null)
            {
                (((ITree)t).ChildIndex)=index;
            }
        }
        public virtual int GetChildIndex(object t, int index)
        {
            if (t != null)
            {
                return index = (((ITree)t).ChildIndex);
            }
            return -1;
        }
        public virtual int GetChildIndex(object t)
        {
            if (t != null)
            {
                return  (((ITree)t).ChildIndex);
            }
            return -1;
        }
        public virtual object GetParent(object t)
        {
            if (t != null)
            {
                return ((ITree)t).Parent;
            }
            return null;
        }
        public virtual void SetParent(object t, object parent)
        {
            if (t != null)
            {
                ((ITree)t).Parent = (ITree)parent;
            }
        }
        public virtual object DeleteChild(object t, int i)
        {
            if (t != null)
            {
                return ((ITree)t).DeleteChild(i);
            }
            return null;
        }
        public virtual void SetChild(object t, int i, object child)
        {
            if (t != null)
            {
                ((ITree)t).SetChild(i, (ITree)child);
            }
        }
        public virtual void SetText(object t, string text)
        {
            SetNodeText(t, text);
        }
        public virtual void SetType(object t, int type)
        {
            SetNodeType(t, type);
        }
        public virtual void AddChild(object t, object child)
        {
            if (t != null)
            {
                ((ITree)t).AddChild((ITree)child);
            }
        }
        public virtual string GetText(object t)
        {
            return GetNodeText(t);
        }
        public virtual int GetType(object t)
        {
            return GetNodeType(t);
        }
        public virtual object ErrorNode(ITokenStream input, IToken start, IToken stop, RecognitionException e)
        {
         
            return null;
        }
        public virtual object DupTree(object tree)
        {
            if (tree != null)
            {
                return ((Expression)tree).DupTree();
            }
            return null;
        }
        public virtual object BecomeRoot(IToken newRoot, object oldRoot)
        {
            return this.BecomeRoot(this.Create(newRoot), oldRoot);
        }

        public virtual object BecomeRoot(object newRoot, object oldRoot)
        {
            if (oldRoot == null)
                return newRoot;

            ITree child = (ITree)newRoot;
            ITree t = (ITree)oldRoot;
            if (child.IsNil) //newRoot is created from a parser rule.
            {
                if (child.ChildCount > 1)
                    throw new SystemException("more than one node as root (TODO: make exception hierarchy)");
                child = child.GetChild(0);
            }
            if (child == null)
                return newRoot;

            child.AddChild(t);
            return child;
        }

        /// <summary>
        /// Create a null expression with given token: <paramref name="payLoad"/>.
        /// </summary>
        /// <param name="payload"></param>
        /// <returns></returns>
        public virtual object Create(IToken payload)
        {
            IExpressionFactory factory = null;
            Expression exp = null;
            if (payload == null) return new Expression(payload);
            if (_factories.TryGetValue(payload.Type, out factory))
                exp = factory.Create(payload);

            return exp != null ? exp : new Text(payload);
        }
        public virtual object Create(int tokenType, IToken fromToken)
        {
            fromToken = this.CreateToken(fromToken);
            fromToken.Type = tokenType;
            return (ITree)this.Create(fromToken);
        }

        public virtual object Create(int tokenType, string text)
        {
            IToken token = this.CreateToken(tokenType, text);
            return (ITree)this.Create(token);
        }

        public virtual object Create(int tokenType, IToken fromToken, string text)
        {
            fromToken = this.CreateToken(fromToken);
            fromToken.Type = tokenType;
            fromToken.Text = text;
            return (ITree)this.Create(fromToken);
        }
        public virtual object Create(IToken fromToken, string text)
        {
            fromToken = this.CreateToken(fromToken);
           // fromToken.Type = tokenType;
            fromToken.Text = text;
            return (ITree)this.Create(fromToken);
        }
        /// <summary>
        /// Create a new copy of <paramref name="fromToken"/>
        /// </summary>
        /// <param name="fromToken"></param>
        /// <returns></returns>
        public virtual IToken CreateToken(IToken fromToken)
        {
            return new CommonToken(fromToken);
        }
        public virtual IToken CreateToken(int tokenType, string text)
        {
            return new CommonToken(tokenType, text);
        }
        public virtual object DupNode(object treeNode)
        {
            return ((ITree)treeNode).DupNode();
        }
        public virtual object DupNode(int type, object treeNode, string text)
        {
            return DupNode(treeNode);
        }
        public virtual object DupNode(object treeNode, string text)
        {
            return DupNode(treeNode);
        }
        public virtual object DupNode(int type, object treeNode)
        {
            return DupNode(treeNode);
        }
        /*public virtual object DupTree(object tree)
        {
            return ((ITree)tree).DupTree();
        }*/

        public virtual object GetChild(object t, int i)
        {
            return ((ITree)t).GetChild(i);
        }

        public virtual int GetChildCount(object t)
        {
            return ((ITree)t).ChildCount;
        }

        public virtual object GetNilNode()
        {
            return this.Create(null);
        }

        public virtual string GetNodeText(object t)
        {
            return ((ITree)t).Text;
        }

        public virtual int GetNodeType(object t)
        {
            return t != null && (t is ITree) ? (t as ITree).Type : 0;
        }

        public virtual IToken GetToken(object treeNode)
        {
            return (treeNode is Expression) ? (treeNode as Expression).Token : null;
        }
        public virtual int GetTokenStartIndex(object t)
        {
            return ((ITree)t).TokenStartIndex;
        }
        public virtual int GetTokenStopIndex(object t)
        {
            return ((ITree)t).TokenStopIndex;
        }
        public int GetUniqueID(object node)
        {
            return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(node);
        }
        public virtual object Nil()
        {
            return new Expression();
        }
        public virtual bool IsNil(object tree)
        {
            return ((ITree)tree).IsNil;
        }

        public virtual object RulePostProcessing(object root)
        {
            //I must comment the following code, because when rewriting rule it will remove those imaginary tokens in tree root.
            //ITree child = (ITree)root;
            //if (((child != null) && child.IsNil) && (child.ChildCount == 1))
            //{
            //    child = child.GetChild(0);
            //}
            //return child;
            return root;
        }

        public virtual void SetNodeText(object t, string text)
        {
            throw new NotImplementedException("don't know enough about Tree node");
        }

        public virtual void SetNodeType(object t, int type)
        {
            throw new NotImplementedException("don't know enough about Tree node");
        }

        public virtual void SetTokenBoundaries(object t, IToken startToken, IToken stopToken)
        {
            if (t == null) return;
            int tokenIndex = 0;
            int num2 = 0;
            if (startToken != null)
            {
                tokenIndex = startToken.TokenIndex;
            }
            if (stopToken != null)
            {
                num2 = stopToken.TokenIndex;
            }
            ((ITree)t).TokenStartIndex = tokenIndex;
            ((ITree)t).TokenStopIndex = num2;
        }
        #endregion
    }
}